﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using CID.Domain.Infrastructure;
using CID.Tests.Support;
using CID.Domain.Exceptions;

namespace CID.Domain.Tests.Infrastructure
{
    [TestFixture]
    class TemplateTypeTests : BaseFunctionalTests
    {
        private const string Name = "Template Name";
        private const string Description = "Template Description";
        private const string TemplateContentEditorConverterType = "TemplateContentConverter";
        private const string TemplateContentEditorViewName = "TemplateContentEditor";
        private static readonly byte[] Content = new byte[] { 1, 2, 3 };

        private TemplateType templateType;

        public override void SetUp()
        {
            base.SetUp();
            templateType = new TemplateType(Name, Description, TemplateContentEditorConverterType, TemplateContentEditorViewName);
        }

        #region Constructor
        [Test]
        public void CreateNewTemplateType()
        {
            var templateType = new TemplateType(Name, Description, TemplateContentEditorConverterType, TemplateContentEditorViewName);

            Assert.AreEqual(Name, templateType.Name);
            Assert.AreEqual(Description, templateType.Description);
            Assert.AreEqual(TemplateContentEditorConverterType, templateType.TemplateContentEditorConverterType);
            Assert.AreEqual(TemplateContentEditorViewName, templateType.TemplateContentEditorViewName);
            Assert.IsTrue(templateType.Enabled);
            CollectionAssert.IsEmpty(templateType.Templates);
        }
        #endregion

        #region CreateTemplates
        private void AssertTemplate<T>(ITemplate template) where T:ITemplate
        {
            Assert.AreEqual(templateType, template.Type);
            Assert.AreEqual(Name, template.Name);
            Assert.AreEqual(Description, template.Description);
            Assert.AreEqual(Content, template.Content);
            Assert.IsTrue(template.Enabled);
            Assert.IsInstanceOf<T>(template);
            CollectionAssert.Contains(templateType.Templates, template);
        }

        [Test]
        public void CreateDeploymentTemplate_ShouldSucceed()
        {
            var template = templateType.CreateDeploymentTemplate(Name, Description, Content);

            AssertTemplate<DeploymentTemplate>(template);
        }

        [Test]
        public void CreateActivationTemplate_ShouldSucceed()
        {
            var template = templateType.CreateActivationTemplate(Name, Description, Content);

            AssertTemplate<ActivationTemplate>(template);
        }

        [Test]
        public void CreateDeactivationTemplate_ShouldSucceed()
        {
            var template = templateType.CreateDeactivationTemplate(Name, Description, Content);

            AssertTemplate<DeactivationTemplate>(template);
        }

        #endregion

        #region AddTemplate
        [Test]
        public void AddTemplate_NoTemplateAdded_ShouldSucceed()
        {
            var template = StubsBuilder.BuildTemplateStub(templateType);

            templateType.AddTemplate(template);

            Assert.AreEqual(1, templateType.Templates.Count());
            CollectionAssert.Contains(templateType.Templates, template);
        }

        [Test]
        public void AddTemplate_TemplateFromAnotherType_NothingShouldHappen()
        {
            var template = StubsBuilder.BuildTemplateStub(StubsBuilder.BuildTemplateTypeStub());

            templateType.AddTemplate(template);

            Assert.AreEqual(0, templateType.Templates.Count());
            CollectionAssert.DoesNotContain(templateType.Templates, template);
        }

        [Test]
        public void AddTemplate_TemplateWithDifferentNameAlreadyAdded_ShouldSucceed()
        {
            var template1 = StubsBuilder.BuildTemplateStub(templateType, "Template1");
            var template2 = StubsBuilder.BuildTemplateStub(templateType, "Template2");
            
            templateType.AddTemplate(template1);
            templateType.AddTemplate(template2);

            Assert.AreEqual(2, templateType.Templates.Count());
            CollectionAssert.Contains(templateType.Templates, template1);
            CollectionAssert.Contains(templateType.Templates, template2);
        }

        [Test, ExpectedException(typeof(DuplicateChildException))]
        public void AddTemplate_TemplateWithSameNameAlreadyAdded_ShouldThrowException()
        {
            var template1 = StubsBuilder.BuildTemplateStub(templateType, "Template");
            var template2 = StubsBuilder.BuildTemplateStub(templateType, "Template");

            templateType.AddTemplate(template1);
            templateType.AddTemplate(template2);
        }
        #endregion

        #region RemoveTemplate
        [Test]
        public void RemoveTemplate_TemplateAlreadyAdded_ShouldSucceed()
        {
            var template1 = StubsBuilder.BuildTemplateStub(templateType, "Template1");
            var template2 = StubsBuilder.BuildTemplateStub(templateType, "Template2");
            templateType.AddTemplate(template1);
            templateType.AddTemplate(template2);

            templateType.RemoveTemplate(template1);

            Assert.AreEqual(1, templateType.Templates.Count());
            CollectionAssert.DoesNotContain(templateType.Templates, template1);
            CollectionAssert.Contains(templateType.Templates, template2);
        }

        [Test]
        public void RemoveTemplate_TemplateFromAnotherType_NothingShouldHappen()
        {
            var anotherTemplateType = new TemplateType("Another Template", "Another Template description", TemplateContentEditorConverterType, TemplateContentEditorViewName);
            var template1 = StubsBuilder.BuildTemplateStub(templateType, "Template1");
            var template2 = StubsBuilder.BuildTemplateStub(anotherTemplateType, "Template2");
            templateType.AddTemplate(template1);
            anotherTemplateType.AddTemplate(template2);

            templateType.RemoveTemplate(template2);

            Assert.AreEqual(1, templateType.Templates.Count());
            Assert.AreEqual(1, anotherTemplateType.Templates.Count());
            Assert.AreEqual(templateType, template1.Type);
            Assert.AreEqual(anotherTemplateType, template2.Type);
            CollectionAssert.Contains(templateType.Templates, template1);
            CollectionAssert.Contains(anotherTemplateType.Templates, template2);
        }
        #endregion
    }
}
